/*
*Copyright 2021-2023 NERCIS
*
*Licensed under the Apache License, Version 2.0 (the "License");
*you may not use this file except in compliance with the License.
*You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*Unless required by applicable law or agreed to in writing, software
*distributed under the License is distributed on an "AS IS" BASIS,
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*See the License for the specific language governing permissions and
*limitations under the License.
*/

package cn.ac.nercis.pes.community.controller.evaluation.planning;

import cn.ac.nercis.pes.common.constant.evaluation.EvaluationModule;
import cn.ac.nercis.pes.common.constant.project.FinishState;
import cn.ac.nercis.pes.community.component.controls.TreeListCell;
import cn.ac.nercis.pes.community.component.dialog.MessageDialog;
import cn.ac.nercis.pes.community.component.dialog.MessageType;
import cn.ac.nercis.pes.community.controller.base.InitEvalDataLoad;
import cn.ac.nercis.pes.community.model.vo.MenuVO;
import cn.ac.nercis.pes.community.utils.AppStore;
import cn.ac.nercis.pes.community.utils.ControlUtils;
import cn.ac.nercis.pes.community.utils.LogUtils;
import cn.ac.nercis.pes.community.utils.SpringUtils;
import cn.ac.nercis.pes.community.views.evaluation.planning.EvaluationMethodView;
import cn.ac.nercis.pes.community.views.evaluation.planning.RelatedTargetView;
import cn.ac.nercis.pes.model.dto.common.TreeNode;
import cn.ac.nercis.pes.model.dto.knowledge.KmSimpleTargetDTO;
import cn.ac.nercis.pes.service.evaluation.EvaluationRangeService;
import cn.ac.nercis.pes.service.project.SystemProcessService;
import javafx.application.Platform;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.net.URL;
import java.util.List;
import java.util.Objects;
import java.util.ResourceBundle;
import java.util.concurrent.CompletableFuture;

/**
 * 测评内容确认管理控制器
 * @author zpy
 * @version 1.0.0
 */
@Slf4j
public class ContentConfirmController implements Initializable, InitEvalDataLoad {

    @FXML
    private StackPane page;
    @FXML
    private BorderPane bodyPane;
    @FXML
    private AnchorPane emptyPane;
    @FXML
    private ImageView emptyImageView;
    @FXML
    private Label emptyLabel;
    @FXML
    private TreeView<MenuVO> menuTreeView;

    private final EvaluationRangeService evaluationRangeService;
    private final SystemProcessService processService;
    private TreeItem<MenuVO> rootMenu;
    private String currentSystemId;
    private final BooleanProperty enablePaste = new SimpleBooleanProperty(false);

    private KmSimpleTargetDTO currentLayerTarget;
    private MenuVO currentAssetNode;

    public ContentConfirmController() {
        this.evaluationRangeService = SpringUtils.getBean(EvaluationRangeService.class);
        this.processService = SpringUtils.getBean(SystemProcessService.class);
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        ControlUtils.initEmptyImageView(this.emptyImageView, log);
        rootMenu = new TreeItem<>(new MenuVO(0, "", "资产分类与对象数据", ""));
        this.initMenuControl();
    }

    @Override
    public void initializeData(String systemId){
        LogUtils.info(log, "初始化测评内容确认信息...");
        this.currentSystemId = systemId;
        this.loadMenuData();
    }

    private void initMenuControl() {
        menuTreeView.setCellFactory(tree -> new TreeListCell(10, true));
        menuTreeView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
            if (Objects.nonNull(newValue) && Objects.nonNull(newValue.getValue()) && newValue.getValue().getId() == 2) {
                loadContentData(newValue.getValue());
                currentAssetNode = newValue.getValue();
            }
        });
        menuTreeView.setRoot(rootMenu);
        menuTreeView.setShowRoot(false);
    }

    private void loadMenuData() {
        LogUtils.info(log, "获取系统资产树节点数据...");
        LogUtils.record(log, "请求数据:{}", this.currentSystemId);
        CompletableFuture.supplyAsync(() -> evaluationRangeService.findAssetTree(this.currentSystemId))
                .thenAccept(res -> Platform.runLater(() -> {
                    if (res.isSuccess()) {
                        this.bodyPane.setVisible(true);
                        this.emptyPane.setVisible(false);
                        this.initMenuData(res.getData());
                        this.loadMenuStateData();
                    } else {
                        this.bodyPane.setVisible(false);
                        this.emptyPane.setVisible(true);
                        this.emptyLabel.setText(res.getMsg());
                    }
                }))
                .exceptionally((ex) -> {
                    log.error("获取系统资产树节点数据出错!", ex);
                    return null;
                });
    }

    private void initMenuData(List<TreeNode> assetNodes) {
        rootMenu.getChildren().clear();
        TreeItem<MenuVO> defaultSelected = null;
        for (TreeNode ac : assetNodes) {
            if (CollectionUtils.isEmpty(ac.getChildren())) {
                continue;
            }
            var menuItem = new MenuVO(1,ac.getId(),ac.getName(),"none-process-icon");
            TreeItem<MenuVO> acMenus = new TreeItem<>(menuItem);
            for(TreeNode asset : ac.getChildren()){
                FinishState finishState = (FinishState) asset.getData();
                var subMenuItem = new MenuVO(2,asset.getId(),asset.getName(),ControlUtils.finishStateToIcon(finishState));
                subMenuItem.setState(finishState);
                subMenuItem.setData(ac.getName());
                acMenus.getChildren().add(new TreeItem<>(subMenuItem));
                if(Objects.isNull(defaultSelected)){
                    defaultSelected = acMenus.getChildren().get(0);
                }
            }
            rootMenu.getChildren().add(acMenus);
        }
        if (Objects.nonNull(defaultSelected)) {
            menuTreeView.getSelectionModel().select(defaultSelected);
        }
    }

    private void loadMenuStateData() {
        var systemProcess = this.processService.findContentConfirmProcess(this.currentSystemId);
        List<MenuVO> acLabels = rootMenu.getChildren().stream()
                .map(TreeItem::getValue)
                .toList();
        for (MenuVO acLabel : acLabels) {
            EvaluationModule module = EvaluationModule.fromNameByContentConfirm(acLabel.getTitle());
            systemProcess.stream()
                    .filter(sp -> StringUtils.equals(sp.getName(), module.getName())).findFirst()
                    .ifPresent(sp -> {
                        acLabel.setIcon(ControlUtils.finishStateToIcon(sp.getFinishState()));
                        acLabel.setState(sp.getFinishState());
                    });
        }
        menuTreeView.refresh();
    }


    private void loadContentData(MenuVO menuItem){
        CompletableFuture.supplyAsync(() -> evaluationRangeService.isRelatedTarget(menuItem.getCode()))
                .thenAccept(res -> Platform.runLater(() -> {
                    if (res) {
                        gotoEvaluationMethod(menuItem);
                    } else {
                        gotoRelatedTarget(menuItem);
                    }
                }))
                .exceptionally((ex) -> {
                    log.error("检查资产对象是否已关联指标出错!", ex);
                    return null;
                });
    }

    public void gotoEvaluationMethod(@NonNull MenuVO menuItem){
        var methodView = AppStore.getEvaluationView(this.currentSystemId, EvaluationMethodView.class);
        this.bodyPane.setCenter(Objects.requireNonNull(methodView).load());
        if(methodView.getController() instanceof EvaluationMethodController controller){
            controller.initializeData(this.currentSystemId,menuItem);
        }
    }

    public void gotoRelatedTarget(@NonNull MenuVO menuItem){
        var targetView = AppStore.getEvaluationView(this.currentSystemId, RelatedTargetView.class);
        this.bodyPane.setCenter(Objects.requireNonNull(targetView).load());
        if(targetView.getController() instanceof RelatedTargetController controller){
            controller.initializeData(this.currentSystemId,menuItem);
        }
    }

    public void refreshMenu(@NonNull String assetId){
        var menuLabel = rootMenu.getChildren().stream()
                .filter(node->CollectionUtils.isNotEmpty(node.getChildren()))
                .flatMap(node->node.getChildren().stream())
                .map(TreeItem::getValue)
                .filter(item->StringUtils.equals(item.getCode(),assetId))
                .findFirst()
                .orElse(null);
        if (Objects.isNull(menuLabel)) {
            return;
        }
        LogUtils.info(log, "刷新系统资产树节点数据...");
        LogUtils.record(log, "请求数据，systemId：{},data:{}", this.currentSystemId, assetId);
        CompletableFuture.supplyAsync(() -> evaluationRangeService.getAssetTreeNode(this.currentSystemId, assetId))
                .thenAccept(res -> Platform.runLater(() -> {
                    if (res.isSuccess()) {
                        FinishState finishState = (FinishState) res.getData().getData();
                        menuLabel.setIcon(ControlUtils.finishStateToIcon(finishState));
                        menuLabel.setState(finishState);
                        refreshAssetClassMenu(assetId);
                    } else {
                        MessageDialog.builder()
                                .withContainer(this.page)
                                .withType(MessageType.FAIL)
                                .withMessage(res.getMsg())
                                .build().show();
                    }
                }))
                .exceptionally((ex) -> {
                    log.error("刷新系统资产树节点数据出错!", ex);
                    return null;
                });

    }

    private void refreshAssetClassMenu(String assetId) {
        var acMenu = rootMenu.getChildren().stream()
                .filter(node -> existAsset(node, assetId))
                .findFirst().orElse(null);
        if (Objects.isNull(acMenu)) {
            return;
        }
        long finishCount = acMenu.getChildren().stream()
                .map(TreeItem::getValue)
                .filter(item -> StringUtils.equals(item.getIcon(),"finish-process-icon"))
                .count();
        EvaluationModule module = EvaluationModule.fromNameByContentConfirm(acMenu.getValue().getTitle());
        FinishState state = finishCount == acMenu.getChildren().size() ? FinishState.FINISH : FinishState.INCOMPLETE;
        CompletableFuture.supplyAsync(() -> processService.setSystemProcess(this.currentSystemId, module, state))
                .thenAccept(res -> Platform.runLater(() -> {
                    if (res.isSuccess()) {
                        acMenu.getValue().setIcon(ControlUtils.finishStateToIcon(state));
                        acMenu.getValue().setState(state);
                        menuTreeView.refresh();
                    }
                }))
                .exceptionally((ex) -> {
                    log.error("设置测评进度信息出错!", ex);
                    return null;
                });
    }

    private boolean existAsset(TreeItem<MenuVO> acMenu, String assetId) {
        if (CollectionUtils.isEmpty(acMenu.getChildren())) {
            return false;
        }
        return acMenu.getChildren().stream()
                .map(TreeItem::getValue)
                .anyMatch(item -> StringUtils.equals(item.getCode(),assetId));
    }
}